#include <signal.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <errno.h>

#include <proxy_stat.h>
#include <log.h>
#include <Singleton.h>
#include <cgi_control.h>

HTTP_SVR_NS_BEGIN

CProxyStat::CProxyStat (void) :
_statinfo (NULL),
_cgi_control (NULL),
last_web_req_count (0),
last_web_rsp_count (0),
last_helper_req_count (0),
last_helper_rsp_count (0)
{
    memset (last_cgi_req_count, 0x00, sizeof(last_cgi_req_count));
    memset (last_cgi_rsp_count, 0x00, sizeof(last_cgi_rsp_count));
}

CProxyStat::~CProxyStat (void)
{
    TCGIControl::Destroy();
}

CProxyStat* CProxyStat::Instance (void)
{
    return CSingleton<CProxyStat>::Instance ();
}

void CProxyStat::Destroy (void)
{
    return CSingleton<CProxyStat>::Destroy ();
}

static void* map_file (const char* filename, int size)
{
    int fd = ::open(filename, O_RDWR|O_CREAT, 0666);
    void *map = NULL;

    if(fd >= 0)
    {
        if(size > 0){
            if(ftruncate(fd, size)){};
		}
        else
            size = lseek(fd, 0L, SEEK_END);

        if(size > 0)
            map = mmap(0, size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
        ::close(fd);
    } else if(size > 0) {
        map = mmap(0, size, PROT_READ|PROT_WRITE, MAP_ANONYMOUS, -1, 0);
    }

    if(map == MAP_FAILED)
    {
        map = NULL;
    }

    return map;
}

int CProxyStat::open (const char* statfile, const char* cgixmlfile)
{
    if(TGlobal::DaemonInit(cgixmlfile) < 0)
		return -1;

    _cgi_control = TCGIControl::Instance ();

    if (NULL == _cgi_control)
    {
        fprintf (stderr, "get TCGIControl instance failed, msg[%s]\n", strerror(errno));
        return -1;
    }

    if (_cgi_control->open(cgixmlfile) == -1)
    {
        fprintf (stderr, "TCGIControl init failed, msg[%s]\n", strerror(errno));
        return -1;
    }

    _statinfo = (TStatHeadInfo*) map_file (statfile, 0);

    if (NULL == _statinfo)
    {
        fprintf (stderr, "get stat info failed, msg[%s]\n", strerror(errno));
        return -1;
    }

    return 0;
}

int CProxyStat::close (void)
{
    return 0;
}

int CProxyStat::print (void)
{ 
    u_long rate = 0;
 
    TCGIInfo* cgi_list = _cgi_control->get_cgi_info ();
    int cgi_count = _cgi_control->get_cgi_count ();

    TCGIStatData* cgi_stat_data = (TCGIStatData*) (_statinfo->_cgi_data);

    fprintf (stderr, "           [CGI STATISTIC INFO]  [TotalReq]   [ReqRate]   [TotalRsp]  [RspRate]\n");
 
    for (int i = 0; i < cgi_count; ++i)
    {
        fprintf (stderr, "%30s: ", cgi_list[i]._szCgiName);

        //print cgi total request
        fprintf (stderr, " %10lu ", (u_long)(cgi_stat_data[i]._cgi_req_count));

        //print cgi request rate
        rate = 0;
        if (last_cgi_req_count[i] > 0 && cgi_stat_data[i]._cgi_req_count > last_cgi_req_count[i])
        {    
            rate = (cgi_stat_data[i]._cgi_req_count - last_cgi_req_count[i]);
        }
        fprintf (stderr, " %6lu r/s ", rate);
        last_cgi_req_count[i] = cgi_stat_data[i]._cgi_req_count;

        //print cgi total response
        fprintf (stderr, " %10lu ", (u_long)(cgi_stat_data[i]._cgi_rsp_count));

        //print cgi response rate
        rate = 0;
        if (last_cgi_rsp_count[i] > 0 && cgi_stat_data[i]._cgi_rsp_count > last_cgi_rsp_count[i])
        {    
            rate = (cgi_stat_data[i]._cgi_rsp_count - last_cgi_rsp_count[i]);
        }
        fprintf (stderr, " %6lu r/s\n", rate);
        last_cgi_rsp_count[i] = cgi_stat_data[i]._cgi_rsp_count;
    }

    fprintf (stderr, "\n           [WEB STATISTIC INFO] ");

    //print web request
    fprintf (stderr, " %10lu ", (u_long)(_statinfo->_web_req_count));
    //print web request rate
    if (last_web_req_count > 0 && _statinfo->_web_req_count > last_web_req_count)
    {
        rate = (_statinfo->_web_req_count - last_web_req_count);
    }
    fprintf (stderr, " %6lu r/s ", rate);
    last_web_req_count = _statinfo->_web_req_count;

    //print web response 
    fprintf (stderr, " %10lu ", (u_long)(_statinfo->_web_rsp_count));
    //print web response rate
    rate = 0;
    if (last_web_rsp_count > 0 && _statinfo->_web_rsp_count > last_web_rsp_count)
    {
        rate = (_statinfo->_web_rsp_count - last_web_rsp_count);
    }
    fprintf (stderr, " %6lu r/s\n\n", rate);
    last_web_rsp_count = _statinfo->_web_rsp_count;

    fprintf (stderr, "        [HELPER STATISTIC INFO] ");

    //print helper request
    fprintf (stderr, " %10lu ", (u_long)_statinfo->_helper_req_count);
    //print helper request rate
    rate = 0;
    if (last_helper_req_count > 0 && _statinfo->_helper_req_count > last_helper_req_count)
    {
        rate = (_statinfo->_helper_req_count - last_helper_req_count);
    }
    fprintf (stderr, " %6lu r/s ", rate);
    last_helper_req_count = _statinfo->_helper_req_count;

    //print helper response
    fprintf (stderr, " %10lu ", (u_long)(_statinfo->_helper_rsp_count));
    //print helper response rate
    rate = 0;
    if (last_helper_rsp_count > 0 && _statinfo->_helper_rsp_count > last_helper_rsp_count)
    {
        rate = (_statinfo->_helper_rsp_count - last_helper_rsp_count);
    }
    fprintf (stderr, " %6lu r/s ", rate);
    last_helper_rsp_count = _statinfo->_helper_rsp_count;

    //format 
    fprintf (stderr, "\n\n===============================================================================\n\n");

    return 0;
}

HTTP_SVR_NS_END

USING_HTTP_SVR_NS;

int main (int argc, char* argv[])
{
    int c;
    char stat_file[256]     = {'\0'};
    char cgi_conf_file[256] = {'\0'};
    CProxyStat* pTxnStater = CProxyStat::Instance ();

    if (NULL == pTxnStater)
    {
        fprintf (stderr, "get CProxyStat instance failed.\n");
        return -1;
    }

    if (argc < 3)
    {
        fprintf (stderr, "usage: %s -f <stat file> -x cgiconfig.xml\n", argv[0]);

        return 0;
    }

    while ((c = getopt (argc, argv, "f:x:h")) != -1) {
		switch (c) {
		case 'f':
			strncpy (stat_file, optarg, sizeof (stat_file) - 1);
            if (access(stat_file, F_OK) != 0)
            {
                fprintf (stderr, "stat file [%s] read failed, msg[%s]\n", stat_file, strerror(errno));
                return -1;
            }
			break;
		case 'x':
			strncpy (cgi_conf_file, optarg, sizeof (cgi_conf_file) - 1);
            if (access(cgi_conf_file, F_OK) != 0)
            {
                fprintf (stderr, "cgi confi file [%s] read failed, msg[%s]\n", cgi_conf_file, strerror(errno));
                return -1;
            }
			break;
		case 'h':
            fprintf (stderr, "usage: %s -f <stat file> -x config.xml\n", argv[0]);
			return 0;
		default:
            fprintf (stderr, "usage: %s -f <stat file> -x config.xml\n", argv[0]);
			return 0;
		}
	}

    if (pTxnStater->open(stat_file, cgi_conf_file) < 0)
    {
        fprintf (stderr, "init CProxyStat object failed.");
        return -1;
    }

    while (1)
    {
        pTxnStater->print ();
        sleep (1);
    }

    return 0;
}
